home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacFormat 1995 January
/
macformat-020.iso
/
Shareware City
/
Developers
/
apps.to.go
/
DTS.Lib
/
ListVarControl.c
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
NeXTSTEP
RISC OS/Acorn
UTF-8
Wrap
Text File
|
1994-05-04
|
36.6 KB
|
1,472 lines
|
[
TEXT/MPS
]
/*
** Apple Macintosh Developer Technical Support
**
** Program: listvarcontrol.c
** Written by: Eric Soldan
**
** Copyright © 1991 Apple Computer, Inc.
** All rights reserved.
*/
/* You may incorporate this sample code into your applications without
** restriction, though the sample code has been provided "AS IS" and the
** responsibility for its operation is 100% yours. However, what you are
** not permitted to do is to redistribute the source as "DSC Sample Code"
** after having made changes. If you're going to re-distribute the source,
** we require that you make it clear in the source that the code was
** descended from Apple Sample Code, but that you've made changes. */
/*
A number of developers have expressed a desire to have the List Manager support
variable-size cells. In response to this, the List control has been extended to
support variable-size rows and columns.
The first problem is where to store the size for each row and column. This
implementation expects the sizes for the individual column widths to be stored
in row 0, cells 1 through numCols, and the individual row widths to be stored in
column 0, rows 1 through numRows. The values are placed in the cells in decimal
ascii. (This is so that the AppsToGo editor can easily be used to create lists
with variable-size cells. You just enter the decimal ascii value in the editor.)
Any row or column without a decimal ascii entry for the size will get the regular
size for a cell.
Since row 0 and column 0 are used to store the widths, these cells are not available
in the list. They are not displayed, and you can not scroll into them. Due to this,
the list is one column narrower and one row shorter than a regular list.
The variable-size list expects the dataBounds upper-left to be 0,0. Any other
upper-left for the dataBounds will cause the variable-size list to misbehave.
A dataBounds other than 0,0 is very rare, and unnecessary, so it seemed better
to not have the code to support it, than to code for a feature almost never used.
Bit 14 of the mode field needs to be set to true for the list to be converted to
a variable-size list. Also, CLVInitialize() has to be called at some time, or else
the framework will create the list as a regular list. (Start.c is a good place.)
For the most part, the List control is managed just like the regular List control.
If you need to access the List itself, it is stored in the refCon of the List control.
However, since the List Manager calls aren't expecting the list to be of variable-size
cells, you can't make all of the calls to the List Manager you would normally make.
If you create a regular list, and then place decimal ascii values in row 0 and
column 0 (where needed), you can then directly call CLVVariableSizeCells() for that
list, and it will be converted. (If you call CLVVariableSizeCells() directly, you
don't actually need to call CLVInitialize(), as it does this for you.)
Below are the List Manager calls, and how they should be handled when using a
variable-size list:
LActivate:
Call CLActivate().
LAddColumn:
Call CLVAddColumn().
LAddRow:
Call CLVAddRow().
LAddToCell:
Okay to call. Cell won't be drawn, though. Standard list drawing is disabled
when using variable-size cell mode. Call CLVDraw() afterwards to draw the cell.
LAutoScroll:
Call CLVAutoScroll().
LCellSize:
New meaning. You can set the size of a column or row. To do, do the following:
1) LGetCell() for the row or column width to change. Example:
For column 3,
short len, locSize[2];
Point cell;
len = 2 * sizeof(short);
cell.h = 3;
cell.v = 0;
LGetCell(locSize, &len, cell, list);
2) Set the size (2nd word) to new size (locSize[1] = newSize).
3) LSetCell(locSize, len, cell, list);
4) CLVAdjustCellLocs(list)
5) CLVUpdate(list)
LClick:
Call CLVClick().
LClrCell:
Okay to call. Cell won't be drawn, though. Standard list drawing is disabled
when using variable-size cell mode. Call CLVDraw() afterwards to draw the cell.
LDelColumn:
Call LDelColumn(), followed by CLVAdjustCellLocs() and CLVUpdate().
LDelRow:
Call LDelRow(), followed by CLVAdjustCellLocs() and CLVUpdate().
LDispose:
Don't call it. Dispose by DisposeControl(CLViewFromList(list)).
LDoDraw:
Don't call it. The variable-sized control should always have doDraw false.
(You can hide the list by making the control invisible.)
LDraw:
Call CLVDraw().
LFind:
Okay to call.
LGetCell:
Okay to call.
LGetSelect:
Okay to call.
LLastClick:
Okay to call.
LNextCell:
Okay to call.
LRect:
Call CLVGetCellInfo().
It's overkill, since it gets everything, but tough. There aren't too many
occasions for the app to get the cell rect, so I'm not going to have another
call to do it.
LScroll:
Don't call.
LSearch:
Okay to call.
LSetCell:
Okay to call. Cell won't be drawn, though. Standard list drawing is disabled
when using variable-size cell mode. Call CLVDraw() afterwards to draw the cell.
LSetSelect:
Call CLVSetSelect().
LUpdate:
Call CLVUpdate
*/
/*****************************************************************************/
#ifndef __CONTROLS__
#include <Controls.h>
#endif
#ifndef __DTSLib__
#include "DTS.Lib.h"
#endif
#ifndef __ERRORS__
#include <Errors.h>
#endif
#ifndef __LISTCONTROL__
#include "ListControl.h"
#endif
#ifndef __CLPROCS__
#include "ListControlProcs.h"
#endif
#ifndef __MEMORY__
#include <Memory.h>
#endif
#ifndef __PACKAGES__
#include <Packages.h>
#endif
#ifndef __RESOURCES__
#include <Resources.h>
#endif
#ifndef __UTILITIES__
#include "Utilities.h"
#endif
/*****************************************************************************/
typedef pascal void (*LDEFProcPtr)(short lMessage, Boolean lSelect, Rect *lRect, Cell lCell,
short lDataOffset, short lDataLen, ListHandle list);
static ListHandle gCLVList;
static void CLVScrollContent(short h, short v);
static WindowPtr CLVSetClip(ListHandle list);
Boolean gMoveCell;
Point gMoveCellStart, gMoveCellEnd;
/*****************************************************************************/
#pragma segment ListControl
void CLVInitialize(void)
{
if (!gclvVariableSizeCells) {
gclvVariableSizeCells = CLVVariableSizeCells;
gclvGetCellRect = CLVGetCellRect;
gclvUpdate = CLVUpdate;
gclvAutoScroll = CLVAutoScroll;
gclvSetSelect = CLVSetSelect;
gclvClick = CLVClick;
gclvAdjustScrollBars = CLVAdjustScrollBars;
}
}
/*****************************************************************************/
#pragma segment ListControl
static void CLVScrollContent(short h, short v)
{
RgnHandle updateRgn;
Rect rView;
rView = (*gCLVList)->rView;
ScrollRect(&rView, h, v, updateRgn = NewRgn());
CLVUpdate(updateRgn, gCLVList);
DisposeRgn(updateRgn);
}
static pascal void CLVScrollAction(ControlHandle ctl, short part);
static pascal void CLVScrollAction(ControlHandle ctl, short part)
{
short delta, value;
short oldValue, max, dx, dy;
Boolean vert;
Rect rct, rr, rrr;
Point pp, cell;
vert = (((*ctl)->contrlRect.right - (*ctl)->contrlRect.left) == 16);
rct = (*gCLVList)->visible;
CLVGetCellRect(gCLVList, rct.left, rct.top, &rr);
rrr = rr;
switch (part) {
case inPageUp:
pp.h = rr.left;
pp.v = rr.top;
if (vert) {
pp.v -= (*gCLVList)->rView.bottom;
pp.v += (*gCLVList)->rView.top;
pp.v += (rr.bottom - rr.top);
pp.v++;
CLVFindCell(gCLVList, pp, &cell);
CLVGetCellRect(gCLVList, cell.h, cell.v, &rrr);
delta = rrr.top - rr.top;
}
else {
pp.h -= (*gCLVList)->rView.right;
pp.h += (*gCLVList)->rView.left;
pp.h += (rr.right - rr.left);
pp.h++;
CLVFindCell(gCLVList, pp, &cell);
CLVGetCellRect(gCLVList, cell.h, cell.v, &rrr);
delta = rrr.left - rr.left;
}
if (delta > 0) part = inUpButton;
break;
case inPageDown:
pp.h = rr.left;
pp.v = rr.top;
if (vert) {
pp.v += (*gCLVList)->rView.bottom;
pp.v -= (*gCLVList)->rView.top;
pp.v--;
CLVFindCell(gCLVList, pp, &cell);
CLVGetCellRect(gCLVList, cell.h, cell.v, &rrr);
delta = rrr.top - rr.top;
}
else {
pp.h += (*gCLVList)->rView.right;
pp.h -= (*gCLVList)->rView.left;
pp.h--;
CLVFindCell(gCLVList, pp, &cell);
CLVGetCellRect(gCLVList, cell.h, cell.v, &rrr);
delta = rrr.left - rr.left;
}
if (delta < 0) part = inDownButton;
break;
}
switch (part) {
case inUpButton:
for (;;) {
if (vert) {
if (rct.top == 1) break;
--rct.top;
}
if (!vert) {
if (rct.left == 1) break;
--rct.left;
}
CLVGetCellRect(gCLVList, rct.left, rct.top, &rrr);
if (!EmptyRect(&rrr)) break;
}
if (vert) delta = rrr.top - rr.top;
else delta = rrr.left - rr.left;
if (delta > 0) delta = 0;
break;
case inDownButton:
if (vert) delta = rr.bottom - rr.top;
else delta = rr.right - rr.left;
if (delta < 0) delta = 0;
break;
}
if (part) { /* If it was actually in the control. */
pp.h = rr.left;
pp.v = rr.top;
if (vert) pp.v += delta;
else pp.h += delta;
CLVFindCell(gCLVList, pp, &cell);
CLVGetCellRect(gCLVList, cell.h, cell.v, &rrr);
if (vert) delta = rrr.top - rr.top;
else delta = rrr.left - rr.left;
value = (oldValue = GetControlValue(ctl)) + delta;
if (value < 0) value = 0;
if (value > (max = GetControlMaximum(ctl))) value = max;
if (value != oldValue) {
SetControlValue(ctl, value);
dx = (vert) ? 0 : (oldValue - value);
dy = (vert) ? (oldValue - value) : 0;
CLVAdjustScrollBars(gCLVList);
CLVScrollContent(dx, dy);
}
}
}
static Boolean CLVScroll(ControlHandle ctl, short part, Point where);
static Boolean CLVScroll(ControlHandle ctl, short part, Point where)
{
ControlHandle cc;
short oldValue, newValue, vv, dx, dy, nn;
Point pp, cell;
Rect rView, rct;
Boolean vert;
static ControlActionUPP cupp;
oldValue = newValue = GetControlValue(ctl);
switch (part) {
case inThumb:
if (TrackControl(ctl, where, nil)) {
newValue = GetControlValue(ctl);
if (oldValue != newValue) {
if ((*gCLVList)->hScroll) (*gCLVList)->visible.left = 1;
if ((*gCLVList)->vScroll) (*gCLVList)->visible.top = 1;
vert = (((*ctl)->contrlRect.right - (*ctl)->contrlRect.left) == 16);
vv = 0;
if (vert) {
cc = (*gCLVList)->hScroll;
if (cc)
vv = (*cc)->contrlValue;
}
else {
cc = (*gCLVList)->vScroll;
if (cc)
vv = (*cc)->contrlValue;
}
(vert) ? (pp.h = vv, pp.v = newValue) : (pp.h = newValue, pp.v = vv);
rView = (*gCLVList)->rView;
pp.h += rView.left;
pp.v += rView.top;
CLVFindCell(gCLVList, pp, &cell);
CLVGetCellRect(gCLVList, cell.h, cell.v, &rct);
if (vert) nn = newValue + ((rct.bottom - rct.top) / 2);
else nn = newValue + ((rct.right - rct.left) / 2);
(vert) ? (pp.h = vv, pp.v = nn) : (pp.h = nn, pp.v = vv);
pp.h += rView.left;
pp.v += rView.top;
CLVFindCell(gCLVList, pp, &cell);
CLVGetCellRect(gCLVList, cell.h, cell.v, &rct);
OffsetRect(&rct, -rView.left, -rView.top);
newValue = (vert) ? rct.top : rct.left;
SetControlValue(ctl, newValue);
newValue = (*ctl)->contrlValue;
dx = (vert) ? 0 : (oldValue - newValue);
dy = (vert) ? (oldValue - newValue) : 0;
CLVAdjustScrollBars(gCLVList);
CLVScrollContent(dx, dy);
rct = (*gCLVList)->visible;
}
}
break;
default:
if (!cupp) cupp = NewControlActionProc(CLVScrollAction);
TrackControl(ctl, where, cupp);
newValue = GetControlValue(ctl);
break;
}
return((oldValue != newValue) ? true : false);
}
/*****************************************************************************/
#pragma segment ListControl
void CLVUpdate(RgnHandle clipRgn, ListHandle list)
{
WindowPtr oldPort;
Rect vbnds, cbnds, rView;
short xx, yy, cellNum, ofst, len, select;
Point cell;
RgnHandle oldClip, newClip;
GetPort(&oldPort);
SetPort((*list)->port);
rView = (*list)->rView;
GetClip(oldClip = NewRgn());
RectRgn(newClip = NewRgn(), &rView);
SectRgn(newClip, oldClip, newClip);
SectRgn(newClip, clipRgn, newClip);
SetClip(newClip);
vbnds = (*list)->visible;
for (yy = vbnds.top; yy < vbnds.bottom; ++yy) {
for (xx = vbnds.left; xx < vbnds.right; ++xx) {
CLVGetCellInfo(list, xx, yy, &cbnds, &cellNum, &select, &ofst, &len);
cell.h = xx;
cell.v = yy;
CLVCallDefProc(lDrawMsg, select, &cbnds, cell, ofst, len, list);
}
}
SetClip(oldClip);
DisposeRgn(oldClip);
DisposeRgn(newClip);
SetPort(oldPort);
}
/*****************************************************************************/
#pragma segment ListControl
static void CLVCallDefProc(short lMessage, short lSelect, Rect *lRect, Cell lCell,
short lDataOffset, short lDataLen, ListHandle list)
{
Handle ldp;
LDEFProcPtr proc;
if (!(ldp = (*list)->listDefProc)) return;
if (!*ldp) LoadResource(ldp);
if (!*ldp) return;
HLock(ldp);
proc = (LDEFProcPtr)*ldp;
lSelect = (lSelect) ? true: false;
CallListDefProc(((ListDefUPP)proc), lMessage, lSelect, lRect, lCell, lDataOffset, lDataLen, list);
HUnlock(ldp);
}
/*****************************************************************************/
#pragma segment ListControl
Boolean CLVClick(Point mouseLoc, short modifiers, ListHandle list)
{
WindowPtr oldPort, window;
ControlHandle ctl;
RgnHandle oldClip, newClip;
Boolean dbl, tracked, turnOff, doRects, inBounds;
Point cc, dd, cell, lastCell, anchor, ulSel, lrSel, pp, mm;
short cellNum, ofst, len, newsel, oldsel, sense, part, dx, dy, data1len, data2len;
Rect rView, cbnds, rr, rct, dbnds, vbnds;
long ll, ctime;
char selFlags, listFlags;
char data1[256], data2[256];
gMoveCellStart.v = gMoveCellStart.h = gMoveCellEnd.v = gMoveCellEnd.h = -1;
GetPort(&oldPort);
SetPort(window = (*list)->port);
rView = (*list)->rView;
selFlags = (*list)->selFlags;
if (selFlags & lOnlyOne) {
selFlags &= (lNoNilHilite | lUseSense | lOnlyOne);
modifiers &= (0xFFFF - shiftKey - cmdKey);
}
(*list)->clikLoc = mouseLoc;
if (WhichControl(mouseLoc, 0, window, &ctl)) {
if (!(part = FindControl(mouseLoc, window, &ctl))) {
(*list)->clikTime = 0L;
return(false);
}
if ((ctl == (*list)->hScroll) || (ctl == (*list)->vScroll)) {
gCLVList = list;
tracked = CLVScroll(ctl, part, mouseLoc);
return(false);
}
}
if (!PtInRect(mouseLoc, &rView)) {
(*list)->clikTime = 0L;
return(false);
}
CLVFindCell(list, mouseLoc, &cell);
(*list)->clikLoc = mouseLoc;
if (cell.h == -1) {
(*list)->clikTime = 0L;
return(false);
}
if (gMoveCell) gMoveCellStart = cell;
CLVGetCellInfo(list, cell.h, cell.v, &cbnds, &cellNum, &sense, &ofst, &len);
GetClip(oldClip = NewRgn());
RectRgn(newClip = NewRgn(), &rView);
SectRgn(newClip, oldClip, newClip);
SetClip(newClip);
ulSel.h = ulSel.v = 0x7FFF;
lrSel.h = lrSel.v = 0;
if (selFlags & lUseSense) {
if (modifiers & shiftKey) {
modifiers |= cmdKey;
}
}
cc.h = cc.v = 1;
turnOff = true;
if (modifiers & shiftKey) {
if (!(selFlags & lUseSense)) turnOff = false;
if (!sense) turnOff = false;
if (selFlags & lNoExtend) turnOff = false;
}
else {
if (modifiers & cmdKey) turnOff = false;
if (sense) turnOff = false;
}
while (LGetSelect(true, &cc, list)) {
CLVGetCellInfo(list, cc.h, cc.v, &cbnds, &cellNum, &oldsel, &ofst, &len);
if (turnOff) {
if ((cell.h != cc.h) || (cell.v != cc.v)) {
(*list)->cellArray[cellNum] &= 0x7FFF;
CLVCallDefProc(lHiliteMsg, false, &cbnds, cc, ofst, len, list);
}
}
else {
if (ulSel.v > cc.v) ulSel.v = cc.v;
if (ulSel.h > cc.h) ulSel.h = cc.h;
if (lrSel.v < cc.v) lrSel.v = cc.v;
if (lrSel.h < cc.h) lrSel.h = cc.h;
if (selFlags & lNoDisjoint) {
(*list)->cellArray[cellNum] &= 0x7FFF;
CLVCallDefProc(lHiliteMsg, false, &cbnds, cc, ofst, len, list);
}
}
if (!LNextCell(true, true, &cc, list)) break;
}
anchor = cell;
if (!(selFlags & lNoExtend)) {
if (lrSel.v) {
for (;;) {
if (cell.h <= ulSel.h) {
anchor = lrSel;
break;
}
if (cell.v <= ulSel.v) {
anchor = lrSel;
break;
}
anchor = ulSel;
break;
}
}
}
lastCell.h = lastCell.v = -1;
cc = (*list)->lastClick;
dbl = ((cc.h == cell.h) && (cc.v == cell.v)) ? true : false;
(*list)->lastClick = cell;
ctime = (*list)->clikTime;
(*list)->clikTime = TickCount();
doRects = true;
do {
if ((cell.h != lastCell.h) || (cell.v != lastCell.v)) {
for (;;) {
if (doRects) {
if (modifiers & shiftKey) {
rr.top = (cell.v < anchor.v) ? cell.v : anchor.v;
rr.left = (cell.h < anchor.h) ? cell.h : anchor.h;
rr.bottom = (cell.v > anchor.v) ? cell.v : anchor.v;
rr.right = (cell.h > anchor.h) ? cell.h : anchor.h;
++rr.bottom;
++rr.right;
cc.h = cc.v = 1;
turnOff = true;
if (selFlags & lNoExtend) turnOff = false;
if (turnOff) {
while (LGetSelect(true, &cc, list)) {
if (!PtInRect(cc, &rr)) {
CLVGetCellInfo(list, cc.h, cc.v, &cbnds, &cellNum,
&oldsel, &ofst, &len);
(*list)->cellArray[cellNum] &= 0x7FFF;
CLVCallDefProc(lHiliteMsg, false, &cbnds, cc, ofst, len, list);
}
if (!LNextCell(true, true, &cc, list)) break;
}
}
for (cc.v = rr.top; cc.v < rr.bottom; ++cc.v) {
for (cc.h = rr.left; cc.h < rr.right; ++cc.h) {
oldsel = (LGetSelect(false, &cc, list)) ? 0x8000 : 0x0000;
newsel = 0x8000;
if (selFlags & lUseSense)
newsel = sense ^ 0x8000;
if (selFlags & lNoNilHilite)
if (!len)
newsel = 0;
if (newsel != oldsel) {
CLVGetCellInfo(list, cc.h, cc.v, &cbnds, &cellNum,
&oldsel, &ofst, &len);
(*list)->cellArray[cellNum] &= 0x7FFF;
(*list)->cellArray[cellNum] |= newsel;
CLVCallDefProc(lHiliteMsg, newsel, &cbnds, cc, ofst, len, list);
}
}
}
if (selFlags & lNoRect) doRects = false;
break;
}
}
if (lastCell.h != -1) {
oldsel = (LGetSelect(false, &lastCell, list)) ? 0x8000 : 0x0000;
newsel = 0;
if (modifiers & cmdKey) newsel = (sense ^ 0x8000);
else {
if (selFlags & lNoRect)
if (modifiers & shiftKey)
newsel = 0x8000;
}
if (selFlags & lExtendDrag)
if (!(modifiers & (cmdKey | shiftKey)))
newsel = 0x8000;
if (newsel != oldsel) {
CLVGetCellInfo(list, lastCell.h, lastCell.v, &cbnds, &cellNum,
&oldsel, &ofst, &len);
(*list)->cellArray[cellNum] &= 0x7FFF;
(*list)->cellArray[cellNum] |= newsel;
CLVCallDefProc(lHiliteMsg, false, &cbnds, lastCell, ofst, len, list);
}
}
if (cell.h != -1) {
oldsel = (LGetSelect(false, &cell, list)) ? 0x8000 : 0x0000;
newsel = 0x8000;
if (modifiers & cmdKey) newsel = (sense ^ 0x8000);
if (selFlags & lNoNilHilite)
if (!len)
newsel = 0;
if (newsel != oldsel) {
CLVGetCellInfo(list, cell.h, cell.v, &cbnds, &cellNum,
&oldsel, &ofst, &len);
(*list)->cellArray[cellNum] &= 0x7FFF;
(*list)->cellArray[cellNum] |= newsel;
CLVCallDefProc(lHiliteMsg, newsel, &cbnds, cc, ofst, len, list);
}
}
break;
}
}
GetMouse(&mouseLoc);
lastCell = cell;
dbnds = (*list)->dataBounds;
CLVGetCellRect(list, dbnds.right - 1, dbnds.bottom - 1, &rct);
rr = rView;
rr.right = rct.right;
rr.bottom = rct.bottom;
SectRect(&rView, &rr, &rr);
ll = PinRect(&rr, mouseLoc);
mm = *(Point *)≪
CLVFindCell(list, mm, &cc);
if (!EqualPt(cc, lastCell)) {
cell = lastCell;
if (cc.h > lastCell.h) ++cell.h;
if (cc.h < lastCell.h) --cell.h;
if (cc.v > lastCell.v) ++cell.v;
if (cc.v < lastCell.v) --cell.v;
if (gMoveCell) {
data1len = data2len = 256;
LGetCell(data1, &data1len, cell, list);
LGetCell(data2, &data2len, lastCell, list);
LSetCell(data1, data1len, lastCell, list);
LSetCell(data2, data2len, cell, list);
CLVGetCellInfo(list, cell.h, cell.v, &cbnds, &cellNum, &sense, &ofst, &len);
CLVCallDefProc(lDrawMsg, sense, &cbnds, cell, ofst, len, list);
CLVGetCellInfo(list, lastCell.h, lastCell.v, &cbnds, &cellNum, &sense, &ofst, &len);
CLVCallDefProc(lDrawMsg, sense, &cbnds, cell, ofst, len, list);
gMoveCellEnd = cell;
}
continue;
}
if (!PtInRect(mouseLoc, &rView)) {
listFlags = (*list)->listFlags;
vbnds = (*list)->visible;
dx = dy = 0;
if (listFlags & lDoHAutoscroll) {
if (mouseLoc.h < rView.left) dx = -1;
if (mouseLoc.h >= rView.right) dx = 1;
}
if (listFlags & lDoVAutoscroll) {
if (mouseLoc.v < rView.top) dy = -1;
if (mouseLoc.v >= rView.bottom) dy = 1;
}
CLVGetCellRect(list, vbnds.right - 1, vbnds.bottom - 1, &rct);
if (dx == 1)
if (vbnds.right >= dbnds.right)
if (rct.right <= rView.right)
dx = 0;
if (dy == 1)
if (vbnds.bottom >= dbnds.bottom)
if (rct.bottom <= rView.bottom)
dy = 0;
if (dx | dy) {
pp.h = (*list)->visible.left;
pp.v = (*list)->visible.top;
cc = pp;
for (;;) {
inBounds = false;
cc.h += dx;
cc.v += dy;
if (!cc.h) break;
if (!cc.v) break;
if (cc.h == dbnds.right) break;
if (cc.v == dbnds.bottom) break;
inBounds = true;
CLVGetCellRect(list, cc.h, cc.v, &rr);
if (!EmptyRect(&rr)) break;
}
if (inBounds) {
CLVGetCellRect(list, pp.h, pp.v, &rct);
gCLVList = list;
dx = rr.left - rct.left;
dy = rr.top - rct.top;
SetClip(oldClip);
ctl = (*list)->hScroll;
if (ctl)
SetControlValue(ctl, (*ctl)->contrlValue + dx);
ctl = (*list)->vScroll;
if (ctl)
SetControlValue(ctl, (*ctl)->contrlValue + dy);
SetClip(newClip);
CLVAdjustScrollBars(list);
CLVScrollContent(-dx, -dy);
CLVGetCellRect(list, dbnds.right - 1, dbnds.bottom - 1, &rct);
rr = rView;
rr.right = rct.right;
rr.bottom = rct.bottom;
SectRect(&rView, &rr, &rr);
ll = PinRect(&rr, mouseLoc);
mm = *(Point *)≪
CLVFindCell(list, mm, &cell);
if (gMoveCell) {
if (cell.v >= 0) {
cc = lastCell;
for (cc = lastCell; !EqualPt(cc, cell); cc = dd) {
dd = cc;
if (dd.h < cell.h) ++dd.h;
if (dd.h > cell.h) --dd.h;
if (dd.v < cell.v) ++dd.v;
if (dd.v > cell.v) --dd.v;
data1len = data2len = 256;
LGetCell(data1, &data1len, cc, list);
LGetCell(data2, &data2len, dd, list);
LSetCell(data1, data1len, dd, list);
LSetCell(data2, data2len, cc, list);
CLVGetCellInfo(list, cc.h, cc.v, &cbnds, &cellNum, &sense, &ofst, &len);
CLVCallDefProc(lDrawMsg, sense, &cbnds, cell, ofst, len, list);
CLVGetCellInfo(list, dd.h, dd.v, &cbnds, &cellNum, &sense, &ofst, &len);
CLVCallDefProc(lDrawMsg, sense, &cbnds, cell, ofst, len, list);
gMoveCellEnd = cell;
}
}
}
}
}
}
} while (StillDown());
SetClip(oldClip);
DisposeRgn(oldClip);
DisposeRgn(newClip);
SetPort(oldPort);
if (dbl) {
cc = (*list)->lastClick;
if ((cc.h == cell.h) && (cc.v == cell.v)) {
if (TickCount() > (ctime + GetDblTime()))
dbl = false;
else
(*list)->clikTime = 0L;
}
else {
dbl = false;
(*list)->clikTime = 0L;
}
}
return(dbl);
}
/*****************************************************************************/
#pragma segment ListControl
static WindowPtr CLVSetClip(ListHandle list)
{
static WindowPtr oldPort;
WindowPtr window;
static RgnHandle oldClip;
RgnHandle newClip;
Rect rView;
if (list) {
GetPort(&oldPort);
SetPort(window = (*list)->port);
rView = (*list)->rView;
GetClip(oldClip = NewRgn());
RectRgn(newClip = NewRgn(), &rView);
SectRgn(newClip, oldClip, newClip);
SetClip(newClip);
DisposeRgn(newClip);
}
else {
SetClip(oldClip);
SetPort(oldPort);
}
return(window);
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
#pragma segment ListControl
void CLVVariableSizeCells(ListHandle list)
{
ControlHandle viewCtl;
CLDataHndl listData;
short mode, len;
short locSize[2];
Rect dbnds;
Point cell;
Str255 pstr;
CLVInitialize();
if (!(viewCtl = CLViewFromList(list))) return;
listData = (CLDataHndl)(*viewCtl)->contrlData;
mode = (*listData)->mode;
if (mode & clVariable) return; /* List already variable mode. */
mode |= clVariable;
(*listData)->mode = mode;
LSetDrawingMode(false, list); /* We're doing it now. Don't let List Manager play. */
dbnds = (*list)->dataBounds;
for (locSize[0] = cell.h = cell.v = 0; ++cell.h < dbnds.right;) {
len = 255;
LGetCell(pstr + 1, &len, cell, list);
pstr[0] = len;
locSize[1] = (pstr[0]) ? p2dec(pstr, nil) : (*list)->cellSize.h;
LSetCell(locSize, (2 * sizeof(short)), cell, list);
locSize[0] += locSize[1];
}
for (locSize[0] = cell.h = cell.v = 0; ++cell.v < dbnds.bottom;) {
len = 255;
LGetCell(pstr + 1, &len, cell, list);
pstr[0] = len;
locSize[1] = (pstr[0]) ? p2dec(pstr, nil) : (*list)->cellSize.v;
LSetCell(locSize, (2 * sizeof(short)), cell, list);
locSize[0] += locSize[1];
}
CLVAdjustScrollBars(list); /* Fix scrollbars to reflect the size of the List. */
/* This also fixes the visible field of the list. */
}
/*****************************************************************************/
/* Figure out which cells are at least partially visible. It's a pain...
** This also saves the visible cells rect into (*list)->visible so that other functions
** can get it quicker than the below hunk-o-code. */
#pragma segment ListControl
void CLVGetVisCells(ListHandle list, Rect *vbnds)
{
Rect rView, cellRct, rct;
ControlHandle ctl;
short len, locSize[2], dx, dy;
Point cell;
*vbnds = (*list)->dataBounds;
rView = (*list)->rView;
ctl = (*list)->hScroll;
if (ctl) dx = (*ctl)->contrlValue;
else {
cell.v = 0;
if (!(cell.h = (*list)->visible.left)) ++cell.h;
len = 2 * sizeof(short);
LGetCell(locSize, &len, cell, list);
dx = locSize[0];
}
ctl = (*list)->vScroll;
if (ctl) dy = (*ctl)->contrlValue;
else {
cell.h = 0;
if (!(cell.v = (*list)->visible.top)) ++cell.v;
len = 2 * sizeof(short);
LGetCell(locSize, &len, cell, list);
dy = locSize[0];
}
OffsetRect(&rView, dx, dy);
(*list)->visible.left = (*list)->visible.top = 1;
for (; vbnds->left < vbnds->right; ++vbnds->left) {
CLVGetCellRect(list, vbnds->left, 1, &cellRct);
cellRct.top = rView.top;
cellRct.bottom = rView.bottom;
SectRect(&rView, &cellRct, &rct);
if (!EmptyRect(&rct)) break;
}
for (; vbnds->right > vbnds->left;) {
CLVGetCellRect(list, --vbnds->right, 1, &cellRct);
cellRct.top = rView.top;
cellRct.bottom = rView.bottom;
SectRect(&rView, &cellRct, &rct);
if (!EmptyRect(&rct)) {
++vbnds->right;
break;
}
}
for (; vbnds->top < vbnds->bottom; ++vbnds->top) {
CLVGetCellRect(list, 1, vbnds->top, &cellRct);
cellRct.left = rView.left;
cellRct.right = rView.right;
SectRect(&rView, &cellRct, &rct);
if (!EmptyRect(&rct)) break;
}
for (; vbnds->bottom > vbnds->top;) {
CLVGetCellRect(list, 1, --vbnds->bottom, &cellRct);
cellRct.left = rView.left;
cellRct.right = rView.right;
SectRect(&rView, &cellRct, &rct);
if (!EmptyRect(&rct)) {
++vbnds->bottom;
break;
}
}
(*list)->visible = *vbnds;
return;
}
/*****************************************************************************/
/* This function looks up the position of cell x,y by getting the info from
** x,0 and 0,y cells. Row 0 and column 0 are never displayed. They hold the
** row and column sizes. */
#pragma segment ListControl
void CLVGetCellRect(ListHandle list, short xx, short yy, Rect *cbnds)
{
Point cell;
short len, locSize[2], dx, dy;
if ((!xx) || (!yy)) {
SetRect(cbnds, 0, 0, 0, 0);
return;
}
cell.h = 0;
cell.v = yy;
len = 2 * sizeof(short);
LGetCell(locSize, &len, cell, list);
cbnds->top = locSize[0];
cbnds->bottom = locSize[0] + locSize[1];
cell.h = xx;
cell.v = 0;
len = 2 * sizeof(short);
LGetCell(locSize, &len, cell, list);
cbnds->left = locSize[0];
cbnds->right = locSize[0] + locSize[1];
OffsetRect(cbnds, (*list)->rView.left, (*list)->rView.top);
if (!(cell.h = (*list)->visible.left)) ++cell.h;
cell.v = 0;
len = 2 * sizeof(short);
LGetCell(locSize, &len, cell, list);
dx = locSize[0];
cell.h = 0;
if (!(cell.v = (*list)->visible.top)) ++cell.v;
len = 2 * sizeof(short);
LGetCell(locSize, &len, cell, list);
dy = locSize[0];
OffsetRect(cbnds, -dx, -dy);
}
/*****************************************************************************/
#pragma segment ListControl
void CLVFindCell(ListHandle list, Point mouseLoc, Point *cell)
{
Rect dbnds, rrct, rct;
short xx, yy;
dbnds = (*list)->dataBounds;
CLVGetCellRect(list, 1, 1, &rct);
rrct.left = rct.left;
CLVGetCellRect(list, dbnds.right - 1, 1, &rct);
rrct.right = rct.right;
for (yy = dbnds.top; yy < dbnds.bottom; ++yy) {
CLVGetCellRect(list, 1, yy, &rct);
rrct.top = rct.top;
rrct.bottom = rct.bottom;
if (PtInRect(mouseLoc, &rrct)) break;
}
if (yy < dbnds.bottom) {
for (xx = dbnds.left; xx < dbnds.right; ++xx) {
CLVGetCellRect(list, xx, yy, &rct);
if (PtInRect(mouseLoc, &rct)) {
cell->h = xx;
cell->v = yy;
return;
}
}
}
cell->h = cell->v = -1;
return;
}
/*****************************************************************************/
#pragma segment ListControl
void CLVGetCellInfo(ListHandle list, short xx, short yy, Rect *cbnds, short *cellNum,
short *select, short *ofst, short *len)
{
short ww;
CLVGetCellRect(list, xx, yy, cbnds);
ww = (*list)->dataBounds.right - (*list)->dataBounds.left;
*cellNum = ww * yy + xx;
*ofst = (*list)->cellArray[*cellNum];
*len = (*list)->cellArray[*cellNum + 1] & 0x7FFF;
*select = *ofst & 0x8000;
*ofst &= 0x7FFF;
*len -= *ofst;
}
/*****************************************************************************/
#pragma segment ListControl
void CLVAdjustScrollBars(ListHandle list)
{
Rect rView, dbnds, rct;
short oldx, oldy, max;
ControlHandle ctl;
Point pp, cell;
rView = (*list)->rView;
dbnds = (*list)->dataBounds;
++rView.right; /* Account for the fact that the top of a rect is in, whereas the */
++rView.bottom; /* bottom of a rect is out. This makes top and bottom the same. */
if ((*list)->hScroll) (*list)->visible.left = 1;
if ((*list)->vScroll) (*list)->visible.top = 1;
oldx = oldy = 0;
ctl = (*list)->hScroll;
if (ctl) {
oldx = (*ctl)->contrlValue;
CLVGetCellRect(list, dbnds.right - 1, 1, &rct);
max = rct.right - rView.right;
if (max < 0) max = 0;
else {
pp.h = rView.left + max;
pp.v = rView.top;
CLVFindCell(list, pp, &cell);
CLVGetCellRect(list, cell.h, cell.v, &rct);
max = rct.right - rView.left;
}
SetControlMaximum(ctl, max);
}
ctl = (*list)->vScroll;
if (ctl) {
oldy = (*ctl)->contrlValue;
CLVGetCellRect(list, 1, dbnds.bottom - 1, &rct);
max = rct.bottom - rView.bottom;
if (max < 0) max = 0;
else {
pp.h = rView.left;
pp.v = rView.top + max;
CLVFindCell(list, pp, &cell);
CLVGetCellRect(list, cell.h, cell.v, &rct);
max = rct.bottom - rView.top;
}
SetControlMaximum(ctl, max);
}
CLVGetVisCells(list, &rct); /* Calc vis area and store in list. */
}
/*****************************************************************************/
#pragma segment ListControl
void CLVSetSelect(Boolean select, Point cell, ListHandle list)
{
WindowPtr oldPort;
RgnHandle oldClip, newClip;
Rect rView, cbnds;
short cellNum, oldsel, newsel, ofst, len;
GetPort(&oldPort);
SetPort((*list)->port);
rView = (*list)->rView;
GetClip(oldClip = NewRgn());
RectRgn(newClip = NewRgn(), &rView);
SectRgn(newClip, oldClip, newClip);
SetClip(newClip);
CLVGetCellInfo(list, cell.h, cell.v, &cbnds, &cellNum, &oldsel, &ofst, &len);
newsel = (select) ? 0x8000 : 0x0000;
if (newsel != oldsel) {
(*list)->cellArray[cellNum] &= 0x7FFF;
(*list)->cellArray[cellNum] |= newsel;
CLVCallDefProc(lHiliteMsg, newsel, &cbnds, cell, ofst, len, list);
}
SetClip(oldClip);
DisposeRgn(oldClip);
DisposeRgn(newClip);
SetPort(oldPort);
}
/*****************************************************************************/
#pragma segment ListControl
void CLVAutoScroll(ListHandle list)
{
WindowPtr oldPort;
RgnHandle oldClip, newClip;
Rect rView, dbnds, vbnds, rct, rr;
Point cell, cc, pp;
short dx, dy, ddx, ddy;
ControlHandle ctl;
Boolean inBounds;
ddx = ddy = 0;
cell.h = cell.v = 1;
if (LGetSelect(true, &cell, list)) {
rView = (*list)->rView;
dbnds = (*list)->dataBounds;
vbnds = (*list)->visible;
while ((!PtInRect(cell, &vbnds))) {
if (EmptyRect(&vbnds)) return;
/* This shouldn't happen, but it would be bad if it did. */
dx = dy = 0;
if (cell.h < vbnds.left) dx = -1;
if (cell.h >= vbnds.right) dx = 1;
if (cell.v < vbnds.top) dy = -1;
if (cell.v >= vbnds.bottom) dy = 1;
CLVGetCellRect(list, vbnds.right - 1, vbnds.bottom - 1, &rct);
if (dx == 1)
if (vbnds.right >= dbnds.right)
if (rct.right <= rView.right)
dx = 0;
if (dy == 1)
if (vbnds.bottom >= dbnds.bottom)
if (rct.bottom <= rView.bottom)
dy = 0;
if ((!dx) && (!dy)) break;
pp.h = (*list)->visible.left;
pp.v = (*list)->visible.top;
cc = pp;
for (;;) {
inBounds = false;
cc.h += dx;
cc.v += dy;
if (!cc.h) break;
if (!cc.v) break;
if (cc.h == dbnds.right) break;
if (cc.v == dbnds.bottom) break;
inBounds = true;
CLVGetCellRect(list, cc.h, cc.v, &rr);
if (!EmptyRect(&rr)) break;
}
if (!inBounds) break;
CLVGetCellRect(list, pp.h, pp.v, &rct);
ddx += rr.left - rct.left;
ddy += rr.top - rct.top;
OffsetRect(&vbnds, dx, dy);
(*list)->visible = vbnds;
ctl = (*list)->hScroll;
if (ctl) (*ctl)->contrlValue += ddx;
ctl = (*list)->vScroll;
if (ctl) (*ctl)->contrlValue += ddy;
CLVGetVisCells(list, &vbnds);
ctl = (*list)->hScroll;
if (ctl) (*ctl)->contrlValue -= ddx;
ctl = (*list)->vScroll;
if (ctl) (*ctl)->contrlValue -= ddy;
}
if ((ddx) || (ddy)) {
GetPort(&oldPort);
SetPort((*list)->port);
ctl = (*list)->hScroll;
if (ctl) SetControlValue(ctl, (*ctl)->contrlValue + ddx);
ctl = (*list)->vScroll;
if (ctl) SetControlValue(ctl, (*ctl)->contrlValue + ddy);
GetClip(oldClip = NewRgn());
RectRgn(newClip = NewRgn(), &rView);
SectRgn(newClip, oldClip, newClip);
SetClip(newClip);
CLVAdjustScrollBars(list);
gCLVList = list;
ctl = CLViewFromList(list);
if ((*ctl)->contrlVis)
CLVScrollContent(-ddx, -ddy);
SetClip(oldClip);
DisposeRgn(oldClip);
DisposeRgn(newClip);
SetPort(oldPort);
}
}
}
/*****************************************************************************/
#pragma segment ListControl
void CLVAdjustCellLocs(ListHandle list)
{
short len, locSize[2], ls[2];
Rect dbnds;
Point cell;
dbnds = (*list)->dataBounds;
for (locSize[0] = cell.h = cell.v = 0; ++cell.h < dbnds.right;) {
len = 2 * sizeof(short);
LGetCell(ls, &len, cell, list);
locSize[1] = ls[1];
LSetCell(locSize, len, cell, list);
locSize[0] += locSize[1];
}
for (locSize[0] = cell.h = cell.v = 0; ++cell.v < dbnds.bottom;) {
len = 2 * sizeof(short);
LGetCell(ls, &len, cell, list);
locSize[1] = ls[1];
LSetCell(locSize, len, cell, list);
locSize[0] += locSize[1];
}
CLVAdjustScrollBars(list);
}
/*****************************************************************************/
#pragma segment ListControl
short CLVAddColumn(short count, short colNum, short ww, ListHandle list)
{
short rval, locSize[2], xx;
Point cell;
rval = LAddColumn(count, colNum, list);
cell.v = 0;
locSize[0] = 0;
locSize[1] = ww;
for (xx = 0; xx < count; ++xx) {
cell.h = rval + xx;
LSetCell(locSize, (2 * sizeof(short)), cell, list);
}
CLVAdjustCellLocs(list);
return(rval);
}
/*****************************************************************************/
#pragma segment ListControl
short CLVAddRow(short count, short rowNum, short hh, ListHandle list)
{
short rval, locSize[2], yy;
Point cell;
rval = LAddRow(count, rowNum, list);
cell.h = 0;
locSize[0] = 0;
locSize[1] = hh;
for (yy = 0; yy < count; ++yy) {
cell.v = rval + yy;
LSetCell(locSize, (2 * sizeof(short)), cell, list);
}
CLVAdjustCellLocs(list);
return(rval);
}
/*****************************************************************************/
#pragma segment ListControl
void CLVDraw(Point cell, ListHandle list)
{
Rect cbnds;
short cellNum, select, ofst, len;
if (list) {
CLVSetClip(list);
CLVGetCellInfo(list, cell.h, cell.v, &cbnds, &cellNum, &select, &ofst, &len);
CLVCallDefProc(lDrawMsg, select, &cbnds, cell, ofst, len, list);
CLVSetClip(nil);
}
}